package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.service.IInteractionReplyService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author 林云
 * @since 2023-08-13
 */
@Service
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {

    private final IInteractionReplyService replyService;

    private final UserClient userClient;

    private final SearchClient searchClient;

    private final CourseClient courseClient;

    private final CatalogueClient catalogueClient;

    private final CategoryCache categoryCache;

    /**
     * 新增互动问题
     */
    @Override
    public void saveQuestion(QuestionFormDTO dto) {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.转换成po
        InteractionQuestion question = BeanUtils.copyBean(dto, InteractionQuestion.class);
        question.setUserId(userId);
        //3.保存
        this.save(question);
    }

    /**
     * 编辑互动问题
     */
    @Override
    public void updateQuestion(Long id, QuestionFormDTO dto) {
        //1.由于没加validated，所以需要手动校验
        if (StringUtils.isBlank(dto.getTitle()) || StringUtils.isBlank(dto.getDescription()) || dto.getAnonymity() == null) {
            throw new BadRequestException("错误参数");
        }
        //2.判断该问题是否存在
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new DbException("该互动问题不存在");
        }
        //3.不能修改别人的
        Long userId = UserContext.getUser();
        if (!userId.equals(question.getUserId())) {
            throw new BadRequestException("不能修改别人的问题");
        }
        //3.设置字段
        question.setTitle(dto.getTitle());
        question.setDescription(dto.getDescription());
        question.setAnonymity(dto.getAnonymity());
        //5.更新
        this.updateById(question);
    }

    /**
     * 分页查询互动问题-用户端
     */
    @Override
    public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery query) {
        //1.校验参数courseId
        if (query.getCourseId() == null) {
            throw new BadRequestException("课程id不能为空");
        }
        //2.查询互动问题
        Long userId = UserContext.getUser();
        Page<InteractionQuestion> page = this.lambdaQuery().eq(InteractionQuestion::getCourseId, query.getCourseId())
                //还要忽略description字段
                .select(InteractionQuestion.class, tableFieldInfo -> !tableFieldInfo.getProperty().equals("description"))
                .eq(query.getOnlyMine(), InteractionQuestion::getUserId, userId)//onlyMine为true才加userId
                //sectionId可有可无，需要判断
                .eq(query.getSectionId() != null, InteractionQuestion::getSectionId, query.getSectionId())
                .eq(InteractionQuestion::getHidden, false)//不隐藏
                .page(query.toMpPageDefaultSortByCreateTimeDesc());//创建时间倒序
        List<InteractionQuestion> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);//返回空的分页数据
        }
        //3.查询最近回答的id
        Set<Long> latestAnswerIds = new HashSet<>();
        Set<Long> userIds = new HashSet<>();
        for (InteractionQuestion question : records) {
            //非匿名才加
            if (!question.getAnonymity()) {
                userIds.add(question.getUserId());
            }
            //刚发布的可能没人回答
            if (question.getLatestAnswerId() != null) {
                latestAnswerIds.add(question.getLatestAnswerId());
            }
        }
        //获取最新回答信息 然后装在Map里
        Map<Long, InteractionReply> replyMap = new HashMap<>();
        if (CollUtils.isNotEmpty(latestAnswerIds)) {
            // in批量查询 不隐藏
            List<InteractionReply> replyList = replyService.list(Wrappers.<InteractionReply>lambdaQuery()
                    .in(InteractionReply::getId, latestAnswerIds)
                    .eq(InteractionReply::getHidden, false));
            for (InteractionReply reply : replyList) {
                if (!reply.getAnonymity()) {
                    userIds.add(reply.getUserId());
                }
                replyMap.put(reply.getId(), reply);
            }
        }

        //4.获取用户信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        //封装为map id->user
        Map<Long, UserDTO> userMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c));


        //5.封装vo
        List<QuestionVO> list = new ArrayList<>();
        for (InteractionQuestion question : records) {
            QuestionVO questionVO = BeanUtils.copyBean(question, QuestionVO.class);
            //如果是匿名，不加用户名和用户头像
            if (!questionVO.getAnonymity()) {
                UserDTO userDTO = userMap.get(questionVO.getUserId());
                if (userDTO != null) {
                    questionVO.setUserName(userDTO.getName());
                    questionVO.setUserIcon(userDTO.getIcon());
                }
            }
            //获取最新回答人
            InteractionReply reply = replyMap.get(question.getLatestAnswerId());
            if (reply != null) {
                //非匿名才去查用户
                if (!reply.getAnonymity()) {
                    UserDTO userDTO = userMap.get(reply.getUserId());
                    if (userDTO != null) {
                        questionVO.setLatestReplyUser(userDTO.getName());
                    }
                }
                questionVO.setLatestReplyContent(reply.getContent());
            }
            list.add(questionVO);
        }
        return PageDTO.of(page, list);
    }

    /**
     * 查询问题详情-用户端
     */
    @Override
    public QuestionVO queryQuestionById(Long id) {
        //校验参数
        if (id == null) {
            throw new BadRequestException("问题id不能为空");
        }
        //查询问题详情
        InteractionQuestion question = this.getById(id);
        //封装vo
        if (question == null) {
            throw new DbException("问题不存在");
        }
        //如果是隐藏的则返回空
        if (question.getHidden()) {
            return null;
        }
        QuestionVO questionVO = BeanUtils.copyBean(question, QuestionVO.class);
        //非匿名则设置用户名和头像
        if (!question.getAnonymity()) {
            UserDTO user = userClient.queryUserById(question.getUserId());//远程调用
            if (user != null) {
                questionVO.setUserName(user.getName());
                questionVO.setUserIcon(user.getIcon());
            }
        }
        return questionVO;
    }

    /**
     * 分页查询互动问题-管理端
     */
    @Override
    public PageDTO<QuestionAdminVO> queryQuestionAdminPage(QuestionAdminPageQuery query) {
        //1.使用es 通过关键词查询课程的id列表
        List<Long> cIds = null;
        if (StringUtils.isNotBlank(query.getCourseName())) {
            cIds = searchClient.queryCoursesIdByName(query.getCourseName());
            //查不出id，后面肯定也没数据，直接返回
            if (CollUtils.isEmpty(cIds)) {
                return PageDTO.empty(0L, 0L);
            }
        }
        //2.分页查询互动问题 条件: courseId beginTime endTime status
        Page<InteractionQuestion> page = this.lambdaQuery()
                .eq(query.getStatus() != null, InteractionQuestion::getStatus, query.getStatus())
                .between(query.getBeginTime() != null && query.getEndTime() != null,
                        InteractionQuestion::getCreateTime,
                        query.getBeginTime(), query.getEndTime())
                .in(CollUtils.isNotEmpty(cIds), InteractionQuestion::getCourseId, cIds)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        //查不到返回空页
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(0L, 0L);
        }
        //3.远程查询用户列表
        Set<Long> userIds = new HashSet<>(); //用户id列表
        Set<Long> courseIds = new HashSet<>(); //课程id列表
        Set<Long> chapterAndSectionIds = new HashSet<>(); //章节id列表
        for (InteractionQuestion record : records) {
            userIds.add(record.getUserId());
            courseIds.add(record.getCourseId());
            chapterAndSectionIds.add(record.getChapterId());
            chapterAndSectionIds.add(record.getSectionId());
        }
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        //将用户列表提取为 id -> user
        if (CollUtils.isEmpty(userDTOS)) {
            throw new BizIllegalException("用户不存在");
        }
        Map<Long, UserDTO> userMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c));

        //4.远程查询课程列表
        List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(courseList)) {
            throw new BizIllegalException("课程不存在");
        }
        //将课程列表提取为 id -> course
        Map<Long, CourseSimpleInfoDTO> courseMap = courseList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));

        //5.远程查询章节列表
        List<CataSimpleInfoDTO> cataSimpleList = catalogueClient.batchQueryCatalogue(chapterAndSectionIds);
        if (CollUtils.isEmpty(cataSimpleList)) {
            throw new BizIllegalException("章节不存在");
        }
        Map<Long, String> cataNameMap = cataSimpleList.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, c -> c.getName()));


        List<QuestionAdminVO> voList = new ArrayList<>();
        for (InteractionQuestion question : records) {
            QuestionAdminVO vo = BeanUtils.copyBean(question, QuestionAdminVO.class);
            UserDTO userDTO = userMap.get(question.getUserId());
            if (userDTO != null) {
                vo.setUserName(userDTO.getName());
            }
            CourseSimpleInfoDTO courseDTO = courseMap.get(question.getCourseId());
            if (courseDTO != null) {
                vo.setCourseName(courseDTO.getName());
                List<Long> categoryIds = courseDTO.getCategoryIds();
                //使用缓存查询三级分类
                String categoryNames = categoryCache.getCategoryNames(categoryIds);
                vo.setCategoryName(categoryNames);
            }
            vo.setChapterName(cataNameMap.get(question.getChapterId()));
            vo.setSectionName(cataNameMap.get(question.getSectionId()));
            voList.add(vo);
        }
        //封装vo
        return PageDTO.of(page, voList);
    }

}
